#pragma once

#include <stdint.h>

enum ChunkSize{
    FRAGMENT_SIZE = 256u,
    RING_SIZE = (5u << 20),
    MSG_SIZE = (132u << 10),
};
enum ChunkPoolSize{
    FRAGMENT_POOL_SIZE  = 4096u,
    RING_POOL_SIZE = 128u,
    MSG_POOL_SIZE = 2048u,
};



class MemoryPool 
{
private:
    struct MemoryStack {
        uint64_t* stack;
        uint32_t top;
    };
    void* base_; //continuous memory base addr 
    uint32_t size_;
    uint32_t chunk_pad_;
    uint32_t chunk_num_; 
    uint32_t chunk_size_;
    struct MemoryStack chunk_allocator_;
public:
    MemoryPool(void* addr, uint32_t size, uint32_t ck_num, uint32_t ck_size);
    ~MemoryPool();
    void* MemoryPoolAlloc();
    int MemoryPoolFree(void* chunk);
    
    inline uint32_t get_chunk_num() const { return chunk_allocator_.top; }
    const void *base() const 
    {
        return base_;
    }
};



class MemoryManager
{
private:
    MemoryPool *ring_pool_ = nullptr;//4MB, just for server
    MemoryPool *msg_pool_ = nullptr; // 129KB
    MemoryPool *fragment_pool_ = nullptr;//64B
    void *memory_ = nullptr;
    uint64_t memory_size_ = 0;
    uint32_t max_msg_size_ = 0;
    void* mr_ = nullptr;
public:
    MemoryManager(void* memory, uint32_t memory_size, uint32_t max_msg_size);
    ~MemoryManager();
    int Init();
    void Destroy();
    void* AllocFrag();
    int FreeFrag(void *buf);

    void* AllocMsg();
    int FreeMsg(void *buf);

    void* AllocRing();
    int FreeRing(void *buf);
    void *memory() {return memory_;}
    uint64_t memory_size() {return memory_size_;}
    uint32_t max_msg_size() {return max_msg_size_;}
    void* mr() {return mr_;}
    void set_mr(void* mr) {mr_ = mr;}
    bool is_ring_buf(void* buf) 
    {
        return reinterpret_cast<uint64_t>(ring_pool_->base()) <= reinterpret_cast<uint64_t>(buf);

    }
    //void add_ref_cnt(){ ref_cnt_++;}
};

